package com.qiaoba.module.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qiaoba.api.system.constant.SysDictConstant;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.module.system.converter.SysDictConverter;
import com.qiaoba.module.system.entity.SysDictData;
import com.qiaoba.module.system.entity.dto.SysDictDataDTO;
import com.qiaoba.module.system.entity.param.SysDictDataParam;
import com.qiaoba.module.system.mapper.SysDictDataMapper;
import com.qiaoba.module.system.service.SysDictDataService;
import com.qiaoba.nosql.redis.service.RedisService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 字典数据 服务层实现
 *
 * @author ailanyin
 * @date 2023-09-10 17:39:33
 */
@Service
@RequiredArgsConstructor
public class SysDictDataServiceImpl implements SysDictDataService {

    private final SysDictDataMapper sysDictDataMapper;
    private final RedisService redisService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(SysDictDataDTO dto) {
        // 校验合法性
        checkDictLabelUnique(dto.getDictCode(), dto.getDictType(), dto.getDictLabel());
        checkDictValueUnique(dto.getDictCode(), dto.getDictType(), dto.getDictValue());

        int result = sysDictDataMapper.insert(SysDictConverter.dto2Entity(dto));
        if (result > 0) {
            // 同步缓存
            cacheDictData(dto.getDictType());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int update(SysDictDataDTO dto) {
        // 校验合法性
        checkDictValueUnique(dto.getDictCode(), dto.getDictType(), dto.getDictValue());
        checkDictLabelUnique(dto.getDictCode(), dto.getDictType(), dto.getDictLabel());

        int result = sysDictDataMapper.updateById(SysDictConverter.dto2Entity(dto));
        if (result > 0) {
            // 同步缓存
            cacheDictData(dto.getDictType());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(List<String> ids) {
        // 要删除的数据是同属于某一个Type的数据, 所以取0号的Type
        SysDictData sysDictData = selectById(ids.get(0), false);
        int result = sysDictDataMapper.deleteBatchIds(ids);
        if (result > 0) {
            cacheDictData(sysDictData.getDictType());
        }
        return result;
    }

    @Override
    public SysDictData selectById(String dictCode, boolean allowNull) {
        SysDictData sysDictData = sysDictDataMapper.selectById(dictCode);
        if (!allowNull && Objects.isNull(sysDictData)) {
            throw new ServiceException(StrUtil.format("字典数据查询为空, ID: {}", dictCode));
        }
        return sysDictData;
    }

    @Override
    public List<SysDictData> selectList(SysDictDataParam param) {
        return sysDictDataMapper.selectList(SysDictConverter.param2Wrapper(param));
    }

    @Override
    public List<SysDictData> selectByDictType(String dictType) {
        return sysDictDataMapper.selectList(SysDictConverter.param2Wrapper(new SysDictDataParam(dictType)));
    }

    @Override
    public List<SysDictData> selectFromCache(String dictType) {
        return redisService.getObjectList(SysDictConstant.SYS_DICT_KEY + dictType, SysDictData.class);
    }

    @Override
    public void resetDictCache() {
        Map<String, List<SysDictData>> dictDataMap = selectList(new SysDictDataParam()).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
        for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet()) {
            redisService.set(SysDictConstant.SYS_DICT_KEY + entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
        }
    }

    @Override
    public String selectDictLabel(String dictType, String dictValue) {
        QueryWrapper<SysDictData> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(SysDictData::getDictType, dictType)
                .eq(SysDictData::getDictValue, dictValue);
        SysDictData sysDictData = sysDictDataMapper.selectOne(wrapper);
        return Objects.isNull(sysDictData) ? StrUtil.EMPTY : sysDictData.getDictLabel();
    }

    private void checkDictLabelUnique(String dictCode, String dictType, String dictLabel) {
        if (StrUtil.isNotBlank(sysDictDataMapper.checkDictLabelUnique(dictCode, dictType, dictLabel))) {
            throw new ServiceException("数据标签已存在");
        }
    }

    private void checkDictValueUnique(String dictCode, String dictType, String dictValue) {
        if (StrUtil.isNotBlank(sysDictDataMapper.checkDictValueUnique(dictCode, dictType, dictValue))) {
            throw new ServiceException("数据键值已存在");
        }
    }

    public void cacheDictData(String dictType) {
        List<SysDictData> dictData = selectByDictType(dictType);
        if (CollUtil.isNotEmpty(dictData)) {
            // 新增/修改 重新set
            redisService.set(SysDictConstant.SYS_DICT_KEY + dictType, dictData.stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
        } else {
            // 为空 说明数据库中被删除 Redis同步删除
            redisService.del(SysDictConstant.SYS_DICT_KEY + dictType);
        }
    }
}
